#define _BSD_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include "tlpi.h"
#include "seqnum.h"
#include <unistd.h>
#include <string.h>

#define BACKLOG 50


int
main(int argc, char *argv[])
{
	struct addrinfo hints;
	struct addrinfo *result, *rp;
	int lfd, addrlen, cfd;
#define ADDRSTRLEN	(NI_MAXHOST + NI_MAXSERV + 10)
	char addrStr[ADDRSTRLEN];
	char host[NI_MAXHOST];
	char service[NI_MAXSERV];
	struct sockaddr_storage claddr;
	int cnt = 0;
	int optval;


	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;

	if(getaddrinfo(NULL, PORT_NUM, &hints, &result) != 0)
		errExit("getaddrinfo() failed");

	if(result == NULL)
		fatal("getaddrinfo() return NULL result\n");

	optval = 1;
	for(rp = result; rp != NULL; rp = rp->ai_next)
	{
		cnt ++;

		if((lfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1)
			errExit("socket() failed");

		if(setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
			errExit("setsockopt() failed");

		if(bind(lfd, rp->ai_addr, rp->ai_addrlen) == 0)
			break;

		close(lfd);
	}

	printf("link table len: %d\n", cnt);

	if(rp == NULL)
		fatal("could not bind socket to any address");

	if(listen(lfd, BACKLOG) == -1)
		errExit("listen() failed");

	for(;;)
	{
		addrlen = sizeof(struct sockaddr_storage);
		cfd = accept(lfd, (struct sockaddr *)&claddr, &addrlen);
		if(cfd == -1)
			errExit("accept failed");

		if(getnameinfo((struct sockaddr *)&claddr, addrlen, host, NI_MAXHOST,
								service, NI_MAXSERV, 0) == 0)
			snprintf(addrStr, ADDRSTRLEN, "(%s, %s)", host, service);
		else
			snprintf(addrStr, ADDRSTRLEN, "(?UNKOWN?)");
		printf("Connection from %s\n", addrStr);

		if(close(cfd) == -1)
			errExit("close() cfd failed");
	}

	if(close(lfd) == -1)
		errExit("close lfd failed");
}
